package executor

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"alfred/database"
	"alfred/models"
	"alfred/notification"
)

type Executor struct {
	db       *database.DB
	notifier *notification.Notifier
	workDir  string
}

// NewExecutor 创建新的执行器
func NewExecutor(db *database.DB, notifier *notification.Notifier, workDir string) *Executor {
	return &Executor{
		db:       db,
		notifier: notifier,
		workDir:  workDir,
	}
}

// ExecuteFlow 执行Flow
func (e *Executor) ExecuteFlow(flowID, commitID, branch string) error {
	// 创建Flow执行记录
	flowExecution := &models.FlowExecution{
		FlowID:   flowID,
		CommitID: commitID,
		Branch:   branch,
	}

	if err := e.db.CreateFlowExecution(flowExecution); err != nil {
		return fmt.Errorf("failed to create flow execution: %v", err)
	}

	// 获取Flow信息
	flow, err := e.db.GetFlow(flowID)
	if err != nil {
		return fmt.Errorf("failed to get flow: %v", err)
	}

	// 获取Flow的所有Node
	nodes, err := e.db.GetNodesByFlowID(flowID)
	if err != nil {
		return fmt.Errorf("failed to get nodes: %v", err)
	}

	// 创建工作目录
	flowWorkDir := filepath.Join(e.workDir, flowExecution.ID)
	if err := os.MkdirAll(flowWorkDir, 0755); err != nil {
		return fmt.Errorf("failed to create work directory: %v", err)
	}

	// 使用defer确保无论成功还是失败都清理临时工作目录
	defer func() {
		if cleanErr := os.RemoveAll(flowWorkDir); cleanErr != nil {
			log.Printf("Warning: failed to clean up work directory %s: %v", flowWorkDir, cleanErr)
		} else {
			log.Printf("Cleaned up work directory: %s", flowWorkDir)
		}
	}()

	// 克隆代码仓库
	repoDir := filepath.Join(flowWorkDir, "repo")
	if err := e.cloneRepository(flow, branch, repoDir); err != nil {
		flowExecution.Status = "failed"
		flowExecution.Error = fmt.Sprintf("Failed to clone repository: %v", err)
		endTime := time.Now()
		flowExecution.EndTime = &endTime
		e.db.UpdateFlowExecution(flowExecution)
		e.notifier.SendFailureNotification(flow, flowExecution, err)
		return err
	}

	// 按顺序执行Node
	for _, node := range nodes {
		if err := e.executeNode(flowExecution, node, repoDir); err != nil {
			flowExecution.Status = "failed"
			flowExecution.Error = fmt.Sprintf("Node %s failed: %v", node.Name, err)
			endTime := time.Now()
			flowExecution.EndTime = &endTime
			e.db.UpdateFlowExecution(flowExecution)
			e.notifier.SendFailureNotification(flow, flowExecution, err)
			return err
		}
	}

	// 执行成功
	flowExecution.Status = "success"
	endTime := time.Now()
	flowExecution.EndTime = &endTime
	e.db.UpdateFlowExecution(flowExecution)

	// 发送成功通知
	e.notifier.SendSuccessNotification(flow, flowExecution)

	log.Printf("Flow %s executed successfully", flow.Name)
	return nil
}

// cloneRepository 克隆代码仓库，支持身份验证
func (e *Executor) cloneRepository(flow *models.Flow, branch, targetDir string) error {
	repoURL := flow.RepoURL
	
	// 如果提供了认证信息，构建带认证的URL
	if flow.GitUsername != "" && flow.GitToken != "" {
		// 解析原始URL并添加认证信息
		if strings.HasPrefix(repoURL, "https://") {
			// 移除https://前缀
			urlWithoutProtocol := strings.TrimPrefix(repoURL, "https://")
			// 构建带认证的URL: https://username:token@domain/path
			repoURL = fmt.Sprintf("https://%s:%s@%s", flow.GitUsername, flow.GitToken, urlWithoutProtocol)
		} else if strings.HasPrefix(repoURL, "http://") {
			// 移除http://前缀
			urlWithoutProtocol := strings.TrimPrefix(repoURL, "http://")
			// 构建带认证的URL: http://username:token@domain/path
			repoURL = fmt.Sprintf("http://%s:%s@%s", flow.GitUsername, flow.GitToken, urlWithoutProtocol)
		}
		log.Printf("Using authenticated clone for repository")
	} else {
		log.Printf("Using public clone for repository")
	}
	
	cmd := exec.Command("git", "clone", "-b", branch, repoURL, targetDir)
	
	// 设置环境变量以避免交互式认证提示
	cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0")
	
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("git clone failed: %v, output: %s", err, string(output))
	}
	
	log.Printf("Successfully cloned repository to %s", targetDir)
	return nil
}

// executeNode 执行Node
func (e *Executor) executeNode(flowExecution *models.FlowExecution, node *models.Node, repoDir string) error {
	// 创建Node执行记录
	nodeExecution := &models.NodeExecution{
		FlowExecutionID: flowExecution.ID,
		NodeID:          node.ID,
	}

	if err := e.db.CreateNodeExecution(nodeExecution); err != nil {
		return fmt.Errorf("failed to create node execution: %v", err)
	}

	// 获取Node的所有Action
	actions, err := e.db.GetActionsByNodeID(node.ID)
	if err != nil {
		nodeExecution.Status = "failed"
		nodeExecution.Error = fmt.Sprintf("Failed to get actions: %v", err)
		endTime := time.Now()
		nodeExecution.EndTime = &endTime
		e.db.UpdateNodeExecution(nodeExecution)
		return err
	}

	// 按顺序执行Action
	var nodeOutput strings.Builder
	for _, action := range actions {
		output, err := e.executeAction(nodeExecution, action, repoDir)
		nodeOutput.WriteString(fmt.Sprintf("[%s] %s\n", action.Name, output))
		if err != nil {
			nodeExecution.Status = "failed"
			nodeExecution.Error = fmt.Sprintf("Action %s failed: %v", action.Name, err)
			nodeExecution.Output = nodeOutput.String()
			endTime := time.Now()
			nodeExecution.EndTime = &endTime
			e.db.UpdateNodeExecution(nodeExecution)
			return err
		}
	}

	// Node执行成功
	nodeExecution.Status = "success"
	nodeExecution.Output = nodeOutput.String()
	endTime := time.Now()
	nodeExecution.EndTime = &endTime
	e.db.UpdateNodeExecution(nodeExecution)

	return nil
}

// executeAction 执行Action
func (e *Executor) executeAction(nodeExecution *models.NodeExecution, action *models.Action, repoDir string) (string, error) {
	// 创建Action执行记录
	actionExecution := &models.ActionExecution{
		NodeExecutionID: nodeExecution.ID,
		ActionID:        action.ID,
	}

	if err := e.db.CreateActionExecution(actionExecution); err != nil {
		return "", fmt.Errorf("failed to create action execution: %v", err)
	}

	var cmd *exec.Cmd
	var output bytes.Buffer
	var stderr bytes.Buffer

	switch action.Type {
	case "shell":
		cmd = exec.Command("sh", "-c", action.Content)
	case "python":
		cmd = exec.Command("python3", "-c", action.Content)
	default:
		err := fmt.Errorf("unsupported action type: %s", action.Type)
		actionExecution.Status = "failed"
		actionExecution.Error = err.Error()
		endTime := time.Now()
		actionExecution.EndTime = &endTime
		e.db.UpdateActionExecution(actionExecution)
		return "", err
	}

	// 设置工作目录为代码仓库目录
	cmd.Dir = repoDir
	cmd.Stdout = &output
	cmd.Stderr = &stderr

	// 执行命令
	err := cmd.Run()
	combinedOutput := output.String() + stderr.String()

	if err != nil {
		actionExecution.Status = "failed"
		actionExecution.Error = fmt.Sprintf("Command failed: %v", err)
		actionExecution.Output = combinedOutput
		endTime := time.Now()
		actionExecution.EndTime = &endTime
		e.db.UpdateActionExecution(actionExecution)
		return combinedOutput, err
	}

	// Action执行成功
	actionExecution.Status = "success"
	actionExecution.Output = combinedOutput
	endTime := time.Now()
	actionExecution.EndTime = &endTime
	e.db.UpdateActionExecution(actionExecution)

	return combinedOutput, nil
}
